﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Kay.Test.Udp
{
    public partial class StartUp : Form
    {
        public StartUp()
        {
            InitializeComponent();
        }

        private void StartUp_Load(object sender, System.EventArgs e)
        {
            #region UDPClient
            _udpClient = new UdpClient(6666);
            ThreadPool.QueueUserWorkItem(ReceivedMessage);
            #endregion

            #region UDP Socket
            _udpSocketp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            _udpSocketp.Bind(new IPEndPoint(IPAddress.Any, 6667));
            _udpSocketp.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
            ThreadPool.QueueUserWorkItem(ReceivedMessage1);
            #endregion
        }

        #region UDPClient
        private UdpClient _udpClient;

        private void ReceivedMessage(object o)
        {
            IPEndPoint ipp = null;
            while (true)
            {
                try
                {
                    var bytes = _udpClient.Receive(ref ipp);
                    var str = Encoding.UTF8.GetString(bytes);

                    SetText(ipp.ToString(), str);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    break;
                }
            }
        }

        private void SetText(string ip, string text)
        {
            if (textBox_Messages.InvokeRequired)
            {
                textBox_Messages.Invoke(new Action<string, string>(SetText), ip, text);
                return;
            }

            if (textBox_Messages.Text.Length != 0)
            {
                textBox_Messages.AppendText(Environment.NewLine);
                textBox_Messages.AppendText(Environment.NewLine);
            }

            textBox_Messages.AppendText(ip + " 说：");
            textBox_Messages.AppendText(Environment.NewLine);
            textBox_Messages.AppendText(text);
        }

        private void button_Send_Click(object sender, EventArgs e)
        {
            errorProvider.Clear();
            var strMessage = textBox_Message.Text.Trim();
            if (strMessage == string.Empty)
            {
                errorProvider.SetError(textBox_Message, "请填写消息内容！");
                return;
            }
            var strIp = textBox_Ip.Text.Trim();
            IPAddress ip;
            if (IPAddress.TryParse(strIp, out ip))
            {
                var ipp = new IPEndPoint(ip, 6666);
                //var udp = new UdpClient();
                //_udpClient.Connect(ipp);
                var bytes = Encoding.UTF8.GetBytes(strMessage);
                var lengthBytes = bytes.Length;
                while (lengthBytes != 0)
                {
                    var sendLength = _udpClient.Send(bytes, lengthBytes, ipp);
                    lengthBytes = lengthBytes - sendLength;
                }
                //udp.Close();
                if (textBox_Messages.Text.Length != 0)
                {
                    textBox_Messages.AppendText(Environment.NewLine);
                    textBox_Messages.AppendText(Environment.NewLine);
                }

                textBox_Messages.AppendText("我 说：");
                textBox_Messages.AppendText(Environment.NewLine);
                textBox_Messages.AppendText(strMessage);
            }
            else
            {
                errorProvider.SetError(textBox_Ip, "Ip 地址有误！");
            }
        }

        private void StartUp_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (_udpClient != null)
            {
                _udpClient.Close();
            }
        }

        private void button_Broadcast_Click(object sender, EventArgs e)
        {
            errorProvider.Clear();
            var strMessage = textBox_Message.Text.Trim();
            if (strMessage == string.Empty)
            {
                errorProvider.SetError(textBox_Message, "请填写消息内容！");
                return;
            }
            //var strIp = textBox_Ip.Text.Trim();
            var ipp = new IPEndPoint(IPAddress.Broadcast, 6666);
            //var udp = new UdpClient();
            //_udpClient.Connect(ipp);
            var bytes = Encoding.UTF8.GetBytes(strMessage);
            var lengthBytes = bytes.Length;
            while (lengthBytes != 0)
            {
                var sendLength = _udpClient.Send(bytes, lengthBytes, ipp);
                lengthBytes = lengthBytes - sendLength;
            }
            //udp.Close();
            if (textBox_Messages.Text.Length != 0)
            {
                textBox_Messages.AppendText(Environment.NewLine);
                textBox_Messages.AppendText(Environment.NewLine);
            }

            textBox_Messages.AppendText("我 说：");
            textBox_Messages.AppendText(Environment.NewLine);
            textBox_Messages.AppendText(strMessage);
        }
        #endregion

        #region UDP Socket
        private Socket _udpSocketp;

        private void ReceivedMessage1(object obj)
        {
            var length = 32 + 10 * 3 + 21 * 2;
            var dict = new Dictionary<string, UdpData>();
            while (true)
            {
                EndPoint ipp = new IPEndPoint(IPAddress.Any, 0);
                try
                {
                    var bytes0 = new byte[1024 + length];
                    _udpSocketp.ReceiveFrom(bytes0, ref ipp);
                    var id = Encoding.UTF8.GetString(bytes0, 0, 32);
                    var count = Convert.ToInt32(Encoding.UTF8.GetString(bytes0, 32, 10));
                    var index = Convert.ToInt32(Encoding.UTF8.GetString(bytes0, 32 + 10, 10));
                    var size = Convert.ToInt32(Encoding.UTF8.GetString(bytes0, 32 + 10 + 10, 10));
                    var endPoint = Encoding.UTF8.GetString(bytes0, 32 + 10 + 10 + 10, 21).Trim(char.MinValue);
                    var toEndPoint = Encoding.UTF8.GetString(bytes0, 32 + 10 + 10 + 10 + 21, 21).Trim(char.MinValue);
                    var text = Encoding.UTF8.GetString(bytes0, 32 + 10 + 10 + 10 + 21 + 21, size);
                    if (index != count - 1)
                    {
                        if (dict.ContainsKey(id))
                        {
                            dict[id].Text += text;
                        }
                        else
                        {
                            var data = new UdpData
                            {
                                Id32 = id,
                                Count10 = count,
                                Index10 = index,
                                Size10 = size,
                                EndPoint21 = endPoint,
                                ToEndPoint21 = toEndPoint,
                                Text = text
                            };
                            dict.Add(id, data);
                        }
                    }
                    else
                    {
                        if (dict.ContainsKey(id))
                        {
                            dict[id].Text += text;
                            SetText1(ipp.ToString(), dict[id].Text);
                            dict.Remove(id);
                        }
                        else
                        {
                            SetText1(ipp.ToString(), text);
                        }
                    }
                    //var str = Encoding.UTF8.GetString(bytes0);

                    //SetText1(ipp.ToString(), str);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    break;
                }
            }
        }

        private void SetText1(string ip, string text)
        {
            if (textBox_Messages1.InvokeRequired)
            {
                textBox_Messages1.Invoke(new Action<string, string>(SetText1), ip, text);
                return;
            }

            if (textBox_Messages1.Text.Length != 0)
            {
                textBox_Messages1.AppendText(Environment.NewLine);
                textBox_Messages1.AppendText(Environment.NewLine);
            }

            textBox_Messages1.AppendText(ip + " 说：");
            textBox_Messages1.AppendText(Environment.NewLine);
            textBox_Messages1.AppendText(text);
        }

        private void button_Send1_Click(object sender, EventArgs e)
        {
            errorProvider.Clear();
            var strMessage = textBox_Message1.Text.Trim();
            if (strMessage == string.Empty)
            {
                errorProvider.SetError(textBox_Message1, "请填写消息内容！");
                return;
            }
            var strIp = textBox_Ip1.Text.Trim();
            IPAddress ip;
            if (IPAddress.TryParse(strIp, out ip))
            {
                var ipp = new IPEndPoint(ip, 6667);
                //var udp = new UdpClient();
                //_udpClient.Connect(ipp);
                var bytes = Encoding.UTF8.GetBytes(strMessage);
                var lengthBytes = bytes.Length;

                while (lengthBytes != 0)
                {
                    //var sendLength = _udpSocketp.SendTo(bytes, ipp);
                    var sendLength = _udpSocketp.SendTo(bytes, 1024, SocketFlags.None, ipp);
                    lengthBytes = lengthBytes - sendLength;
                }
                //udp.Close();
                if (textBox_Messages1.Text.Length != 0)
                {
                    textBox_Messages1.AppendText(Environment.NewLine);
                    textBox_Messages1.AppendText(Environment.NewLine);
                }

                textBox_Messages1.AppendText("我 说：");
                textBox_Messages1.AppendText(Environment.NewLine);
                textBox_Messages1.AppendText(strMessage);
            }
            else
            {
                errorProvider.SetError(textBox_Ip1, "Ip 地址有误！");
            }
        }
        #endregion

        private void button_Broadcast1_Click(object sender, EventArgs e)
        {
            errorProvider.Clear();
            var strMessage = textBox_Message1.Text.Trim();
            if (strMessage == string.Empty)
            {
                errorProvider.SetError(textBox_Message, "请填写消息内容！");
                return;
            }
            //var strIp = textBox_Ip.Text.Trim();
            var ipp = new IPEndPoint(IPAddress.Broadcast, 6667);
            //var udp = new UdpClient();
            //_udpClient.Connect(ipp);
            var bytes = Encoding.UTF8.GetBytes(strMessage);
            var lengthBytes = bytes.Length;
            var sendLength1 = 1024;
            var count = (int)Math.Ceiling((decimal)lengthBytes / sendLength1);
            var dataPackage = new UdpData(count, sendLength1, _udpSocketp.LocalEndPoint.ToString(), ipp.ToString());
            for (int i = 0; i < count; i++)
            {
                dataPackage.Index10 = i;
                var sendBytes = new byte[dataPackage.Length + sendLength1];
                Array.Copy(dataPackage.GetBytes(Encoding.UTF8), sendBytes, dataPackage.Length);
                if (bytes.Length - i * sendLength1 < sendLength1)
                {
                    sendLength1 = bytes.Length - i * sendLength1;
                }
                Array.Copy(bytes, i * 1024, sendBytes, dataPackage.Length, sendLength1);
                _udpSocketp.SendTo(sendBytes, ipp);
            }
            //while (lengthBytes > 0)
            //{
            //    var sendLength = _udpSocketp.SendTo(bytes, bytes.Length - lengthBytes, sendLength1, SocketFlags.None, ipp);
            //    lengthBytes = lengthBytes - sendLength;
            //    if (lengthBytes < sendLength1)
            //    {
            //        sendLength1 = lengthBytes;
            //    }
            //}
            //udp.Close();
            if (textBox_Messages1.Text.Length != 0)
            {
                textBox_Messages1.AppendText(Environment.NewLine);
                textBox_Messages1.AppendText(Environment.NewLine);
            }

            textBox_Messages1.AppendText("我 说：");
            textBox_Messages1.AppendText(Environment.NewLine);
            textBox_Messages1.AppendText(strMessage);
        }
    }
}
